#问题：装饰器的用法是什么？

'''
一个装饰器（decorator）就是一个函数，它接受一个函数作为参数并返回一个新的函数。

#基本用法
@decorator
def func(*args, **kwargs):
    pass

#它等价于
def func(*args, **kwargs):
    pass

# func是一个函数对象，只有加了（）才是真正调用这个方法
func = decorator(func)
'''

#元编程 ：创建操作源代码的函数和类，在运行时去改变程序的行为。

#装饰器的本质是一个可调用的对象（通常都是指函数），它的参数是另外一个函数。
#Python 中，@符号就是表示装饰器的语法糖。

registry = []

def register(func):
    print('register func: ', func.__name__)
    registry.append(func)

    return func # 必须返回原函数对象func

# 这里的@register就相当于执行了 func1 = register(func1)
# 如果上面没有返回`func`，那么func1就是一个None，无法去调用它
@register #装饰器在加载模块时是立即执行的
def func1():
    print('running func1')

@register
def func2():
    print('running func2')




#实现一个最简单的计时器装饰器
import time

def timeit(func):
    def wrapper(*args, **kwargs): # 闭包，func是一个自由变量
        """
        This is a wrapper.
        """
        start = time.time()

        # 调用原始函数，并使用*args, **kwargs来接受任意参数，这样就确保了这个装饰器可以作用于任何函数
        # 因为需要在装饰器内部去执行传入的函数，所以要加一层函数的包装器wrapper。
        result = func(*args, **kwargs)
        end = time.time()

        print(func.__name__, end - start) # 该装饰器真正的任务，即对函数实行额外计时的操作
        return result # 返回原始函数调用后的结果
    return wrapper

@timeit
def sleep_time(seconds):
    """
    sleep timer
    """
    time.sleep(seconds)


def main():
    print('registered functions: ', registry)
    func1()
    func2()
    print("===================")
    sleep_time(10)

if __name__ == "__main__":
    main()

#参考文章 https://blog.csdn.net/five3/article/details/83447467